package com.atguigu.tingshu.user.service.impl;

import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSON;
import com.atguigu.tingshu.common.constant.KafkaConstant;
import com.atguigu.tingshu.common.constant.RedisConstant;
import com.atguigu.tingshu.common.service.KafkaService;
import com.atguigu.tingshu.common.util.AuthContextHolder;
import com.atguigu.tingshu.model.user.UserInfo;
import com.atguigu.tingshu.model.user.UserPaidAlbum;
import com.atguigu.tingshu.model.user.UserPaidTrack;
import com.atguigu.tingshu.user.context.UpdateUserPaidRecordStrategyContext;
import com.atguigu.tingshu.user.mapper.UserInfoMapper;
import com.atguigu.tingshu.user.mapper.UserPaidAlbumMapper;
import com.atguigu.tingshu.user.mapper.UserPaidTrackMapper;
import com.atguigu.tingshu.user.service.UserInfoService;
import com.atguigu.tingshu.user.stragegy.UpdateUserPaidRecordStrategy;
import com.atguigu.tingshu.vo.user.UserInfoVo;
import com.atguigu.tingshu.vo.user.UserPaidRecordVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Slf4j
@Service
@SuppressWarnings({"unchecked", "rawtypes"})
public class UserInfoServiceImpl extends ServiceImpl<UserInfoMapper, UserInfo> implements UserInfoService {

	private final UserInfoMapper userInfoMapper;
	private final WxMaService wxMaService ;
	private final KafkaService kafkaService;
	private final RedisTemplate<String,String> redisTemplate;
	private final UserPaidAlbumMapper userPaidAlbumMapper;
	private final UserPaidTrackMapper userPaidTrackMapper;
	@Autowired
	public UserInfoServiceImpl(UserInfoMapper userInfoMapper, WxMaService wxMaService, KafkaService kafkaService, RedisTemplate<String, String> redisTemplate, UserPaidAlbumMapper userPaidAlbumMapper, UserPaidTrackMapper userPaidTrackMapper) {
		this.userInfoMapper = userInfoMapper;
		this.wxMaService = wxMaService;
		this.kafkaService = kafkaService;
		this.redisTemplate = redisTemplate;
		this.userPaidAlbumMapper = userPaidAlbumMapper;
		this.userPaidTrackMapper = userPaidTrackMapper;
	}

	/**
	 * @description: 小程序授权登录
	 * @author Petrichor
	 * @date 2023/12/23 20:13
	 * @param code 前端传来的 临时登录凭证
	 * @return 自定义登陆状态
	 **/
	@Override
	@SneakyThrows
	public Map<String, String> wxLogin(String code) {

		// 请求微信服务完成登录
		WxMaJscode2SessionResult sessionInfo = wxMaService.getUserService().getSessionInfo(code);
		// 用户的唯一标识
		String openid = sessionInfo.getOpenid();
		// 根据openId进行查询
		LambdaQueryWrapper<UserInfo> lambdaQueryWrapper = new LambdaQueryWrapper<>() ;
		lambdaQueryWrapper.eq(UserInfo::getWxOpenId , openid) ;
		UserInfo userInfo = userInfoMapper.selectOne(lambdaQueryWrapper);
		// 判断 该用户是否存在
		if (userInfo == null){
			// 没有注册 则注册
			userInfo = new UserInfo() ;
			userInfo.setNickname("听友: " + System.currentTimeMillis());
			userInfo.setAvatarUrl("https://oss.aliyuncs.com/aliyun_id_photo_bucket/default_handsome.jpg");
			userInfo.setWxOpenId(openid);
			userInfoMapper.insert(userInfo) ;

			// 初始化用户的账户数据，向MQ中发送消息
			kafkaService.sendMsg(KafkaConstant.QUEUE_USER_REGISTER , String.valueOf(userInfo.getId()));
		}
		// 生成token
		String token = UUID.randomUUID().toString().replace("-", "");
		redisTemplate.opsForValue().set(RedisConstant.USER_LOGIN_KEY_PREFIX + token ,
				JSON.toJSONString(userInfo) ,
				RedisConstant.USER_LOGIN_KEY_TIMEOUT ,
				TimeUnit.SECONDS);

		// 构建响应结果
		Map<String , String> result = new HashMap<>() ;
		result.put("token" , token) ;

		// 返回
		return result;
	}
	/**
	 * @description: 获取登录信息
	 * @author Petrichor
	 * @date 2023/12/23 20:56
	 * @return 用户登录信息
	 **/
	@Override
	public UserInfoVo getUserInfoVoByUserId(Long userId) {
		UserInfo userInfo = userInfoMapper.selectById(userId);
		UserInfoVo userInfoVo = new UserInfoVo();
		BeanUtils.copyProperties(userInfo, userInfoVo);
		return userInfoVo;
	}
	/**
	 * @description: 判断用户是否购买声音列表
	 * @author Petrichor
	 * @date 2024/1/1 15:28
	 * @param albumId 专辑id
	 * @param userId 用户id
	 * @param trackIdList 声音id列表
	 * @return
	 **/
	@Override
	public Map<Long, Integer> userIsPaidTrack(Long userId, Long albumId, List<Long> trackIdList) {
		// 创建一个Map集合对象存储响应结果数据
		Map<Long , Integer> result = new HashMap<>() ;

		// 判断当前用户是否购买过专辑
		LambdaQueryWrapper<UserPaidAlbum> userPaidAlbumLambdaQueryWrapper = new LambdaQueryWrapper<>() ;
		userPaidAlbumLambdaQueryWrapper.eq(UserPaidAlbum::getUserId , userId) ;
		userPaidAlbumLambdaQueryWrapper.eq(UserPaidAlbum::getAlbumId , albumId);
		UserPaidAlbum userPaidAlbum = userPaidAlbumMapper.selectOne(userPaidAlbumLambdaQueryWrapper);
		if(userPaidAlbum != null) {
			// 用户购买了专辑
			trackIdList.forEach(trackId -> {
				result.put(trackId , 1) ;			// 1表示的就是购买
			});
		}else {		// 没有购买过专辑
			// 判断是否购买过声音
			LambdaQueryWrapper<UserPaidTrack> userPaidTrackLambdaQueryWrapper = new LambdaQueryWrapper<>() ;
			userPaidTrackLambdaQueryWrapper.eq(UserPaidTrack::getAlbumId , albumId) ;
			userPaidTrackLambdaQueryWrapper.eq(UserPaidTrack::getUserId , userId) ;
			userPaidTrackLambdaQueryWrapper.in(UserPaidTrack::getTrackId , trackIdList) ;
			// 存储的就是购买过的声音数据
			List<UserPaidTrack> userPaidTrackList = userPaidTrackMapper.selectList(userPaidTrackLambdaQueryWrapper);
			List<Long> userPaidTrackIdList = userPaidTrackList.stream().map(userPaidTrack -> userPaidTrack.getTrackId()).collect(Collectors.toList());
			trackIdList.forEach(trackId -> {
				if(userPaidTrackIdList.contains(trackId)) {
					// 保存，购买过
					result.put(trackId , 1) ;			// 1表示的就是购买
				}else {
					result.put(trackId , 0) ;			// 0表示的就是购买
				}
			});

		}

		// 返回
		return result;
	}
	/**
	 * @description: 判断用户是否购买过专辑
	 * @author Petrichor
	 * @date 2024/1/6 16:25
	 * @param albumId 专辑id
	 * @return 是否购买过专辑
	 **/
    @Override
    public Boolean isPaidAlbum(Long albumId) {
		// 获取当前登录用户的id
		Long userId = AuthContextHolder.getUserId();

		// 构建查询条件对象
		LambdaQueryWrapper<UserPaidAlbum> userPaidAlbumLambdaQueryWrapper = new LambdaQueryWrapper<>() ;
		userPaidAlbumLambdaQueryWrapper.eq(UserPaidAlbum::getUserId, userId);
		userPaidAlbumLambdaQueryWrapper.eq(UserPaidAlbum::getAlbumId,albumId);

		// 查询数据
		Long count = userPaidAlbumMapper.selectCount(userPaidAlbumLambdaQueryWrapper);

		// 返回
		return count > 0 ;

    }
	/**
	 * @description: 根据专辑id获取用户支付过的声音id列表
	 * @author Petrichor
	 * @date 2024/1/7 21:31
	 * @param albumId 专辑id
	 * @return 查看当前用户的 当前专辑购买的 声音集数 集合
	 **/
	@Override
	public List<Long> findUserPaidTrackList(Long albumId) {
		// 获取当前登录用户的id
		Long userId = AuthContextHolder.getUserId();

		// 构建条件对象
		LambdaQueryWrapper<UserPaidTrack> userPaidTrackLambdaQueryWrapper = new LambdaQueryWrapper<>();
		userPaidTrackLambdaQueryWrapper.eq(UserPaidTrack::getUserId, userId);
		userPaidTrackLambdaQueryWrapper.eq(UserPaidTrack::getAlbumId, albumId);
		// 查询数据
		List<UserPaidTrack> paidTrackList = userPaidTrackMapper.selectList(userPaidTrackLambdaQueryWrapper);

		// 获取声音的id
		List<Long> trackIdList = paidTrackList.stream().map(userPaidTrack -> userPaidTrack.getTrackId()).collect(Collectors.toList());

		// 返回数据
		return trackIdList ;
	}
	/**
	 * @description: 更新用户支付记录
	 * @author Petrichor
	 * @date 2024/1/8 22:49
	 * @param userPaidRecordVo 用户支付记录对象
	 * @return NULL
	 **/
	@Override
	public void updateUserPaidRecord(UserPaidRecordVo userPaidRecordVo) {
		// 获取到付款类型
		String itemType = userPaidRecordVo.getItemType();
		// 根据付款项目的类型获取对应的策略接口的实现类对象
		UpdateUserPaidRecordStrategy updateUserPaidRecordStrategy =
				UpdateUserPaidRecordStrategyContext.getUpdateUserPaidRecordStrategy(itemType);
		// 调用方法保存交易信息
		updateUserPaidRecordStrategy.updateUserPaidRecord(userPaidRecordVo);
	}
	/**
	 * @description: 更新Vip到期失效状态
	 * @author Petrichor
	 * @date 2024/1/12 19:13
	 * @return NULL
	 **/
	@Override
	public void updateVipExpireStatus() {
		//	获取到当前时间
		Date date = new Date() ;
		LambdaQueryWrapper<UserInfo> wrapper = new LambdaQueryWrapper<>();
		wrapper.eq(UserInfo::getIsVip,1);
		wrapper.select(UserInfo::getId);
		wrapper.lt(UserInfo::getVipExpireTime,date);

		//	查询到当前过期用户列表
		List<UserInfo> userInfoList = this.list(wrapper);

		//	判断当前集合不为空
		if (!CollectionUtils.isEmpty(userInfoList)){
			for (UserInfo userInfo : userInfoList) {
				userInfo.setIsVip(0);
			}
			//	批量更新
			this.saveOrUpdateBatch(userInfoList);
		}
	}
}
